#ifndef _core_dispatch_type_lookup_switch_vector_impl_hpp_
#define _core_dispatch_type_lookup_switch_vector_impl_hpp_

/** \file switch_vector_impl.hpp
 *  \author Adrian Schweizer
 *  \created  $Sa 18 Aug 03:48:01 pm CEST 2007 schwadri@SchwadriComp.local$
 *  \modified $So 30 Sep 04:55:13 pm CEST 2007 schwadri@SchwadriLaptop$
 */

#include "../../limits.hpp"

#include <boost/mpl/vector.hpp>
#include <boost/mpl/begin.hpp>
#include <boost/mpl/next.hpp>
#include <boost/mpl/deref.hpp>

#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/arithmetic/sub.hpp>
#include <boost/preprocessor/repetition/enum.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/preprocessor/iteration/local.hpp>
#include <boost/preprocessor/control/if.hpp>

namespace core {

    namespace dispatch {

        namespace type_lookup {

            //contains switch_ implementation for mpl::map
            namespace vector {

                template<int CasesSize, class Cases, class ReturnValue>
                    struct get_switch_impl_helper;

                //specializations for 0 Switch Cases
                template<class C, class R>
                    struct switch_impl_0
                    {
                        template<class K, class I, class D>
                            static R eval(K key, I invoker, D d, C)
                            {
                                return d(key);
                            }
                    };
                //void ret value
                template<class C>
                    struct switch_impl_0<C,void>
                    {
                        template<class K, class I, class D>
                            static void eval(K key, I invoker, D d, C)
                            {
                                d(key);
                            }
                    };

                template<class C, class R>
                    struct get_switch_impl_helper<0,C,R>
                    {
                        typedef switch_impl_0<C,R> type;
                    };

                #define CORE_GENERATE_GET_SWITCH_IMPL(n)                                    \
                template<class C, class R>                                                  \
                    struct get_switch_impl_helper<n,C,R>                                    \
                    {                                                                       \
                        typedef BOOST_PP_CAT(switch_impl_,n)<C,R> type;                     \
                    };

                #define CORE_BEGIN_ITER        typedef typename boost::mpl::begin<C>::type  iter0;
                #define CORE_NEXT_ITER(n,name) typedef typename boost::mpl::next<BOOST_PP_CAT(name,BOOST_PP_SUB(n,1))>::type  BOOST_PP_CAT(name,n);

                #define CORE_GENERATE_SWITCH_CASE(z,n,data)                                 \
                BOOST_PP_IF(n,CORE_NEXT_ITER(n,iter),CORE_BEGIN_ITER)                       \
                typedef typename boost::mpl::deref<BOOST_PP_CAT(iter,n)>::type              \
                                                    BOOST_PP_CAT(t,n);                      \
                case BOOST_PP_CAT(iter,n)::pos::value:                                      \
                    return invoker.template invoke<BOOST_PP_CAT(t,n)>();                    \
                    break;

                #define CORE_GENERATE_SWITCH_CASE_VOID_RET(z,n,data)                        \
                BOOST_PP_IF(n,CORE_NEXT_ITER(n,iter),CORE_BEGIN_ITER)                       \
                typedef typename boost::mpl::deref<BOOST_PP_CAT(iter,n)>::type              \
                                                    BOOST_PP_CAT(t,n);                      \
                case BOOST_PP_CAT(iter,n)::pos::value:                                      \
                    invoker.template invoke<BOOST_PP_CAT(t,n)>();                           \
                    break;



                #define CORE_GENERATE_SWITCH_IMPL_NON_VOID_RET(n)                           \
                template<class C, class R>                                                  \
                    struct BOOST_PP_CAT(switch_impl_,n)                                     \
                    {                                                                       \
                        template<class K, class I, class D>                                 \
                            static R eval(K key, I invoker, D d, C)                         \
                            {                                                               \
                                switch(key)                                                 \
                                {                                                           \
                                BOOST_PP_REPEAT(n,CORE_GENERATE_SWITCH_CASE,C)              \
                                default:                                                    \
                                    return d(key);                                          \
                                }                                                           \
                            }                                                               \
                    };

                #define CORE_GENERATE_SWITCH_IMPL_VOID_RET(n)                               \
                template<class C>                                                           \
                    struct BOOST_PP_CAT(switch_impl_,n)<C,void>                             \
                    {                                                                       \
                        template<class K, class I, class D>                                 \
                            static void eval(K key, I invoker, D d, C)                      \
                            {                                                               \
                                switch(key)                                                 \
                                {                                                           \
                                BOOST_PP_REPEAT(n,CORE_GENERATE_SWITCH_CASE_VOID_RET,C)     \
                                default:                                                    \
                                    d(key);                                                 \
                                }                                                           \
                            }                                                               \
                    };

                #define CORE_GENERATE_SWITCH_IMPL(n)                \
                        CORE_GENERATE_SWITCH_IMPL_NON_VOID_RET(n)   \
                        CORE_GENERATE_SWITCH_IMPL_VOID_RET(n)

                #define CORE_GENERATE_SWITCH(n)                     \
                        CORE_GENERATE_SWITCH_IMPL(n)                \
                        CORE_GENERATE_GET_SWITCH_IMPL(n)

                #define BOOST_PP_LOCAL_MACRO   CORE_GENERATE_SWITCH
                #define BOOST_PP_LOCAL_LIMITS (1, CORE_LIMIT_SWITCH_MAX_CASES)
                //DO NOT REMOVE WHITESPACE   ^
                #include BOOST_PP_LOCAL_ITERATE()

                #undef CORE_GENERATE_SWITCH
                #undef CORE_GENERATE_SWITCH_IMPL
                #undef CORE_GENERATE_SWITCH_IMPL_VOID_RET
                #undef CORE_GENERATE_SWITCH_IMPL_NON_VOID_RET
                #undef CORE_GENERATE_SWITCH_CASE_VOID_RET
                #undef CORE_GENERATE_SWITCH_CASE
                #undef CORE_GENERATE_GET_SWITCH_IMPL
                #undef CORE_BEGIN_ITER
                #undef CORE_NEXT_ITER


                struct get_switch_impl
                {
                    template<int CasesSize, class Cases, class ReturnValue>
                        struct apply
                        {
                            typedef typename get_switch_impl_helper<CasesSize,Cases,ReturnValue>::type type;
                        };
                };

            } // namespace vector

            namespace detail {

                template<class SequenceTag>
                    struct get_switch_impl;

                #ifdef BOOST_MPL_CFG_TYPEOF_BASED_SEQUENCES
                template<>
                    struct get_switch_impl<boost::mpl::aux::vector_tag>
                    {
                        typedef vector::get_switch_impl     type;
                    };
                #else
                template<BOOST_MPL_AUX_NTTP_DECL(long, N)>
                    struct get_switch_impl<boost::mpl::aux::vector_tag<N> >
                    {
                        typedef vector::get_switch_impl     type;
                    };

                #endif
            }   // namespace detail
        } // namespace type_lookup
    } // namespace dispatch
} // namespace core

#endif // _core_dispatch_type_lookup_switch_vector_impl_hpp_
